#include "TextureManager.h"
#include "sfmlphysfs.hpp"
#include "DebugLog.h"
#ifdef _WINDOWS
	#include <Windows.h>
#endif

TextureManager::TextureManager(void) : _mode(RESOURCE_LOAD_FROM_ARCHIVE)	// default to loading resources from archive
{
	_loadTexFptr[RESOURCE_LOAD_FROM_ARCHIVE] = &TextureManager::loadTextureFromArchive;
	_loadTexFptr[RESOURCE_LOAD_FROM_FILEPATH] = &TextureManager::loadTextureFromFile;
}	
TextureManager::~TextureManager(void){}

TextureManager* TextureManager::_instance = nullptr;

TextureManager* TextureManager::getSingletonPtr()
{
	if (_instance == nullptr)
	{
		_instance = new TextureManager();
	}
	return _instance;
}

void TextureManager::cleanSingleton()
{
	if (_instance != nullptr)
	{
		delete _instance;
		_instance = nullptr;
	}
}

sf::Texture* TextureManager::loadTexture(const std::string& filepath, const std::string& id, bool remove)
{
	sf::Texture* texture = doesTextureExist(id);
	if (texture)
		return texture;
	return (this->*_loadTexFptr[_mode])(filepath, id, remove);
}

inline sf::Texture* TextureManager::loadTextureFromArchive(const std::string& filepath, const std::string& id, bool remove)
{
	if (!PHYSFS_exists(filepath.c_str()))
	{
		Debug::log("ERROR: " + filepath + " does not exist.");
		abort();
	}

	sf::physfs stream(filepath.c_str());

	sf::Texture* texture = new sf::Texture;
	if (!texture->loadFromStream(stream))
	{
		Debug::log("ERROR: could not load " + filepath + " from stream.");
		abort();
	}
	_textures.insert(std::make_pair(id, texture));
	if (remove)
	{
		_removeList.push_back(id);
	}
	return texture;
}

inline sf::Texture* TextureManager::loadTextureFromFile(const std::string& filepath, const std::string& id, bool remove)
{
	sf::Texture* texture = new sf::Texture;
	if (!texture->loadFromFile(filepath))
	{
		Debug::log("ERROR: could not load " + filepath + " from stream.");
		abort();
	}

	_textures.insert(std::make_pair(id, texture));
	if (remove)
	{
		_removeList.push_back(id);
	}
	return texture;
}

void TextureManager::unloadTexture(const std::string& id)
{
	auto it = _textures.find(id);
	if (it != _textures.end())
	{
		delete it->second;
		it->second = nullptr;
		_textures.erase(it);
	}
}

void TextureManager::unloadAllTextures()
{
	for (auto it = _textures.begin(); it != _textures.end(); it++)
	{
		delete it->second;
		it->second = nullptr;
	}
	_textures.clear();
}

sf::Texture* TextureManager::doesTextureExist(const std::string id)
{
	if (!_textures.empty())
	{
		std::map<std::string, sf::Texture*>::iterator it = _textures.find(id);
		if (it == _textures.end())
		{
			return nullptr;
		}
		return it->second;
	}
	return nullptr;
}

void TextureManager::flush()
{
	if (!_removeList.empty())
	{
		for (auto it = _removeList.begin(); it != _removeList.end(); it++)
		{
			_textures.erase(*it);
		}
		_removeList.clear();
	}
}

void TextureManager::setMode(int value)
{
	if (value == RESOURCE_LOAD_FROM_ARCHIVE || value == RESOURCE_LOAD_FROM_FILEPATH)
		_mode = value;
}

